#include <iostream>
using namespace  std;

//1.基本语法
//2.发生异常之后，是跨函数 跨了函数栈
//3.接收异常之后，可以不处理 再抛出异常
//4.catch异常时 按照类型进行catch
//5.异常捕捉严格按照类型匹配,不会进行隐式类型转换

void divide(int x, int y){
        if(y == 0){
                throw x; //抛出int类型异常
        }
        cout<<"x/y"<<x/y<<endl;
}

void myDivid(int x, int y){
        try{
                divide(x, y);
        }catch(...){
               cout<<"我接收了divide异常 但是我没有处理 我向上抛出"<<endl;
               throw ; 
        } 
}

int main01(int argc, char const *argv[]){
        try{
                //divide(10, 2);
                //divide(100, 0);
                myDivid(100, 0);
        }catch(int e){
                cout<<e<<"被零除"<<endl;
        }catch(...){//
                cout<<"其他未知类型异常"<<endl;
        }
        
        return 0;
}

int main02(int argc, char const *argv[]){
        myDivid(100, 0);
        return 0;
}

int main03(int argc, char const *argv[]){
        try{
                throw 'z';
        }catch(int e){
                cout<<"捕获int类型异常"<<endl;
        }catch(...){
                cout<<"未知类型异常"<<endl;
        }
        
        return 0;
}


//栈解旋 发生异常捕捉到后会自动释放栈的空间 调用析够函数
class Test3{
public:
        Test3(int a = 0, int b = 0){
                this->a = a;
                this->b = b;
                cout<<"构造函数do"<<endl;
        }
        ~Test3(){
                cout<<"析够函数do"<<endl;
        }
private:
        int a;
        int b;
};

//void myDivide2() throw (int , char, char *)   //规定只能抛出这几种类型的异常
//void myDivide2() throw() //不抛出任何异常
void myDivide2()//不写 可以抛出任何类型
{ 
        Test3 t1(1, 2), t2(3, 4);
        cout<<"myDivide...要发生异常\n";
        //throw Test3;
       throw 1;
}

int main04(int argc, char const *argv[]){
        try{
                myDivide2();
        }catch(int a){
                cout<<"捕获int类型异常"<<endl; 
        } catch(...){
                cout<<"未知类型异常"<<endl;
        }
                
        return 0;
}

//传统的处理错误的机制
int  my_strcpy(char *to, char *from){
        if(from == NULL ){
                return 1;
        }
        if(to == NULL ){
                return 2;
        }

        //copy时的场景检查
        if(*from == 'a'){
                return 3;
        }
        
        while (*to++ == *from++);
        
        return 0;    
}

int main05(int argc, char const *argv[])
{
        int ret = 0;
        char buf1[] = "abcdefg";
        char buf2[1024];
        ret = my_strcpy(buf2, buf1);
        if(ret  != 0){
                switch (ret)
                {
                case 1:
                        printf("源buf出错\n");
                        break;
                case 2:
                        printf("目的buf出错\n");
                        break;
                case 3:
                        printf("copy过程出错\n");
                        break;
                default:
                        printf("未知错误\n");
                        break;
                }
        }
        return 0;
}

//throw int 类型异常
void  my_strcpy2(char *to, char *from){
        if(from == NULL ){
                throw 1;
        }
        if(to == NULL ){
                throw 2;
        }

        //copy时的场景检查
        if(*from == 'a'){
                throw 3;
        }
        
        while (*to++ == *from++);  
}

//throw char * 类型异常
void  my_strcpy3(char *to, char *from){
        if(from == NULL ){
                throw "源buf出错";
        }
        if(to == NULL ){
                throw "目的buf出错";
        }

        //copy时的场景检查
        if(*from == 'a'){
                throw "copy过程出错";
        }
        
        while (*to++ == *from++);  
}


class BadSrcType {};
class BadDesType {};
class BadProcessType 
{
public:
        BadProcessType(){
                cout<<"BadProcessType 构造函数"<<endl;
        }
        BadProcessType(const BadProcessType &obj){
                cout<<"BadProcessType 拷贝构造函数"<<endl;
        }
        ~BadProcessType(){
                cout<<"BadProcessType析够函数"<<endl;
        }

};
//throw 类对象 类型异常
void  my_strcpy4(char *to, char *from){
        if(from == NULL ){
                throw BadSrcType();
        }
        if(to == NULL ){
                throw BadDesType();
        }

        //copy时的场景检查
        if(*from == 'a'){
                throw  BadProcessType(); //会不会产生一个匿名对象呢?
        }

        if(*from == 'b'){
                //throw &(BadProcessType());
                throw new BadProcessType;
        }
        
        while (*to++ == *from++);  
}

int main06(int argc, char const *argv[]){
        char buf1[] = "bbcdefg ";
        char buf2[1024];

        
        try{
                //my_strcpy2(buf2, buf1);        
                my_strcpy4(buf2, buf1);        
        }catch(int e){//e可以写,也可以不写 传过来了3
               cout<<e<<" 捕获int类型异常"<<endl;  
        }catch(char *e){
                cout<<e<< " 捕获char *类型异常"<<endl;
        }catch(BadSrcType e){
                cout<<" BadSrcType 类型异常"<<endl;  
        } catch(BadDesType e){
                cout<<"BadDesType 类型异常"<<endl;  

        } 
        //1.如果 接收异常的时期 使用一个异常变量, 则copy构造异常变量
        /*catch(BadProcessType e){ //是把匿名对象copy给e 还是e还是那个匿名对象
                cout<<" BadProcessType 类型异常"<<endl;  
        }*/
        //2.使用引用的话 会使用throw时类的那个对象
        /*catch(BadProcessType &e){ 
                cout<<" BadProcessType  引用类型异常"<<endl;  
        }*/
        //3. 指针可以和引用/元素写在一块 但是引用/元素不能写在一块
        catch(BadProcessType *e){ 
                cout<<" BadProcessType  指针类型异常"<<endl;  
                delete e; //这个地方还需要手动释放内存
        } 
        //4.最终在抛异常地方使用普用类型，捕捉异常的地方使用引用类型
        catch(...){
                cout<<"未知类型异常"<<endl;
        }
        
        return 0;
}

class MyArray
{
public:
        MyArray(int len);
        ~MyArray();
public:
        int& operator[](int index);
        int getLen();
        //内部类
        class eSize{
                public:
                        eSize(int size)
                        {
                                m_size = size;
                        }
                        virtual void printErr(){
                                cout<<"size:"<<m_size<<" ";
                        }
                protected:
                        int m_size;
        };
        class eNegative:public eSize
        {
                public:
                        eNegative(int size):eSize(size){
                                ;
                        }
                        virtual void printErr(){
                                cout<<"eNegative size:"<<m_size<<" ";
                        }
        };
        class eZero:public eSize
        {
                public:
                        eZero(int size):eSize(size){
                                ;
                        }
                        virtual void printErr(){
                                cout<<"eZero size:"<<m_size<<" ";
                        }
        };
        class eTooBig:public eSize
        {
                public:
                        eTooBig(int size):eSize(size){
                                ;
                        }
                        virtual void printErr(){
                                cout<<"eTooBig size:"<<m_size<<" ";
                        }
        };
        class eTooSmall:public eSize
        {
                public:
                        eTooSmall(int size):eSize(size){
                                ;
                        }
                        virtual void printErr(){
                                cout<<"eTooSmall size:"<<m_size<<" ";
                        }
        };
        
private:
        int *m_space;
        int m_len;
};

MyArray::MyArray(int len){
        if(len < 0){
                throw eNegative(len);
        }else if(len == 0){
                throw eZero(len);
        }else if(len < 3){
                throw eTooSmall(len);
        }else if(len > 1000){
                throw eTooBig(len);
        }
        m_len = len;
        m_space = new int[len];
}
MyArray::~MyArray(){
        if(m_space != NULL){
                delete [] m_space;
                m_space = NULL;
                m_len = 0;
        }
}

int& MyArray::operator[](int index){
       return m_space[index];
}

int MyArray::getLen(){
        return m_len;
}

//不推荐
int main07(int argc, char const *argv[])
{
        try{
                MyArray a(-5);
                for (int i = 0; i < a.getLen(); i++)
                {
                        a[i] = i+1;
                        printf("%d ", a[i]);
                }
        }
        catch(MyArray::eNegative &e){
                cout<<"MyArray::eNegative 类型异常"<<endl;
        }
        catch(MyArray::eZero &e){
                cout<<"MyArray::eZero 类型异常"<<endl;
        }
        catch(MyArray::eTooBig &e){
                cout<<"MyArray::eTooBig 类型异常"<<endl;
        }
        catch(MyArray::eTooSmall &e){
                cout<<"MyArray::eTooSmall 类型异常"<<endl;
        }
        catch(...){
                cout<<"未知 类型异常"<<endl;
        }          
        return 0;
}

int main08(int argc, char const *argv[])
{
        try{
                MyArray a(-5);
                for (int i = 0; i < a.getLen(); i++)
                {
                        a[i] = i+1;
                        printf("%d ", a[i]);
                }
        }
        catch(MyArray::eSize &e){
                e.printErr();
        }
        catch(...){
                cout<<"未知 类型异常"<<endl;
        }          
        return 0;
}

//标准库的异常
class MyException : public exception{
        public:
                MyException(const char *p){
                        this->m_p = const_cast<char *>(p);
                }
                virtual const char* what(){
                        return m_p;
                }
        private:
                char *m_p;
};
void testMyException(){
        throw MyException("函数异常");
}
int main(int argc, char const *argv[]){
        try
        {
                testMyException();
        }
        catch(MyException&e)
        {
                std::cerr << e.what() << '\n';
        }
        catch(...)
        {
                cout<<"未知异常"<<endl;
        }
        return 0;
}
